home *** CD-ROM | disk | FTP | other *** search
- /* SMTP Server state machine - see RFC 821
- * enhanced 4/88 Dave Trulli nn2z
- *
- * Mods by G1EMM, PA0GRI and KO4KS
- */
- #include <stdio.h>
- #include <time.h>
- #ifdef UNIX
- #include <sys/types.h>
- #endif
- #if defined(__STDC__) || defined(__TURBOC__)
- #include <stdarg.h>
- #endif
- #include <ctype.h>
- #include <setjmp.h>
- #include "global.h"
- #include "config.h"
- #include "mbuf.h"
- #include "cmdparse.h"
- #include "socket.h"
- #ifdef LZW
- #include "lzw.h"
- #endif
- #include "iface.h"
- #include "proc.h"
- #include "smtp.h"
- #include "commands.h"
- #include "dirutil.h"
- #include "mailbox.h"
- #include "mailutil.h"
- #include "bm.h"
- #include "domain.h"
- #include "session.h"
- #include "mailfor.h"
- #ifdef NNTPS
- #include "nntp.h"
- #endif
-
- char *Days[7] = { "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
- char *Months[12] = { "Jan","Feb","Mar","Apr","May","Jun",
- "Jul","Aug","Sep","Oct","Nov","Dec" };
-
-
-
- char *host_or_wpage_exp __ARGS((char *to,int hier,int exphome));
- extern char *wpage_exp __ARGS((char *to,int hier,int exphome));
- extern FILE *fopennew __ARGS((char *fname, char *mode));
- struct list *expandalias __ARGS((struct list **head,char *user,char *orig));
- static int getmsgtxt __ARGS((struct smtpsv *mp));
- static struct smtpsv *mail_create __ARGS((void));
- static void mail_clean __ARGS((struct smtpsv *mp));
- static int mailit __ARGS((FILE *data,char *from,struct list *tolist));
- static int router_queue __ARGS((FILE *data,char *from,struct list *to));
- static void smtplog __ARGS((char *fmt,...));
- static void smtpserv __ARGS((int s,void *unused,void *p));
- int mailuser __ARGS((FILE *data,char *from,char *to,char *origto));
- extern int msgidcheckg __ARGS((char *string));
- extern int rdaemon __ARGS((FILE *data,char *from,char *to,char *msg,char msgtype, int mode));
- #ifdef RMAIL
- extern int rmail __ARGS((FILE *fp, char *from));
- #endif
- #ifdef REQSVR
- extern int reqsvr __ARGS((FILE *fp, char *from));
- #endif
- extern FILE *subdir_fopen __ARGS((char *name, char *mode));
- extern char *nntp_name_expansion __ARGS((char *name));
-
- /* Command table */
- static char *commands[] = {
- "helo",
- #define HELO_CMD 0
- "noop",
- #define NOOP_CMD 1
- "mail from:",
- #define MAIL_CMD 2
- "quit",
- #define QUIT_CMD 3
- "rcpt to:",
- #define RCPT_CMD 4
- "help",
- #define HELP_CMD 5
- "data",
- #define DATA_CMD 6
- "rset",
- #define RSET_CMD 7
- "expn",
- #define EXPN_CMD 8
- #ifdef LZW
- "xlzw",
- #define XLZW_CMD 9
- #endif
- NULLCHAR
- };
-
- /* Reply messages */
- static char Banner[] = "220 %s SMTP ready\n";
- static char Closing[] = "221 Closing\n";
- static char Ok[] = "250 Ok\n";
- static char Reset[] = "250 Reset state\n";
- static char Sent[] = "250 Sent\n";
- static char Ourname[] = "250 %s, Share and Enjoy!\n";
- #ifdef LZW
- static char LZWOk[] = "250 %d %d LZW Ok\n";
- static char Help[] = "214-Commands:\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET EXPN XLZW\n214 End\n";
- #else
- static char Help[] = "214-Commands:\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET EXPN\n214 End\n";
- #endif
- static char Enter[] = "354 Enter mail, end with .\n";
- static char DupBidMsg[] = "550 Duplicate BID found in Message-Id line\n";
- static char Lowmem[] = "421 System overloaded, try again later\n";
- static char Ioerr[] = "452 Temp file write error\n";
- static char Badcmd[] = "500 Command unrecognized\n";
- static char Syntax[] = "501 Syntax error\n";
- static char Needrcpt[] = "503 Need RCPT (recipient)\n";
- static char Unknown[] = "550 <%s> address unknown\n";
- static char Noalias[] = "550 No alias for <%s>\n";
- char DAEMONSTR[] = "%sMAILER-DAEMON@%s (Mail Delivery Subsystem)\n";
-
- static int Ssmtp = -1; /* prototype socket for service */
- int MbHolding = 0;
- extern char *Historyfile;
- #ifdef WPAGES
- extern int MbWpages;
- #endif
- extern int Smtpbidcheck;
-
- #ifdef MSDOS
- /* Valid characters in a DOS filename matrix */
- static unsigned char doschars[] = {
- 0x00, 0x00, 0x00, 0x00, 0xfa, 0x23, 0xff, 0x03,
- 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0x6f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
- static int dosfnchr __ARGS((int ch));
- #endif
-
- /* Start up SMTP receiver service */
- int
- smtp1(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return (installserver (argc, argv, &Ssmtp, "SMTP listener", IPPORT_SMTP,
- "SMTP server", smtpserv, 2048, NULL));
- }
-
- /* Shutdown SMTP service (existing connections are allowed to finish) */
- int
- smtp0(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return (deleteserver (&Ssmtp));
- }
-
- static void
- smtpserv(s,unused,p)
- int s;
- void *unused;
- void *p;
- {
- struct smtpsv *mp;
- char **cmdp,buf[LINELEN],*arg,*cp,*cmd,*newaddr;
- struct list *ap,*list;
- int cnt;
- char address_type;
- char *orig;
- #ifdef LZW
- extern int Smtpslzw;
- int lzwbits, lzwmode;
- #endif
-
- sockmode(s,SOCK_ASCII);
- sockowner(s,Curproc); /* We own it now */
- log(s,"open SMTP");
-
- if((mp = mail_create()) == NULLSMTPSV){
- tprintf(Nospace);
- log(s,"close SMTP - no space");
- close_s(s);
- return;
- }
- mp->s = s;
-
- (void) usprintf(s,Banner,Hostname);
-
- loop: pwait (NULL);
- if ((cnt = recvline(s,buf,sizeof(buf))) == -1){
- /* He closed on us */
- goto quit;
- }
- if(cnt < 4){
- /* Can't be a legal command */
- usprintf(mp->s,Badcmd);
- goto loop;
- }
- rip(buf);
- cmd = buf;
-
- /* Translate entire buffer to lower case */
- for(cp = cmd;*cp != '\0';cp++)
- *cp = tolower(*cp);
-
- /* Find command in table; if not present, return syntax error */
- for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
- if(strncmp(*cmdp,cmd,strlen(*cmdp)) == 0)
- break;
- if(*cmdp == NULLCHAR){
- (void) usprintf(mp->s,Badcmd);
- goto loop;
- }
- arg = &cmd[strlen(*cmdp)];
- /* Skip spaces after command */
- while(*arg == ' ')
- arg++;
- /* Execute specific command */
- switch(cmdp-commands){
- #ifdef LZW
- case XLZW_CMD:
- if(!Smtpslzw) {
- usprintf(mp->s,Badcmd);
- } else {
- lzwmode = lzwbits = 0;
- sscanf(arg,"%d %d",&lzwbits,&lzwmode);
- if(!((lzwmode == 0 || lzwmode == 1)
- && (lzwbits > 8 && lzwbits < 17))) {
- lzwmode = LZWCOMPACT;
- lzwbits = LZWBITS;
- usprintf(mp->s,Badcmd);
- } else {
- usprintf(mp->s,LZWOk,lzwbits,lzwmode);
- lzwinit(mp->s,lzwbits,lzwmode);
- }
- }
- break;
- #endif
- case HELO_CMD:
- free(mp->system);
- mp->system = strdup(arg);
- (void) usprintf(mp->s,Ourname,Hostname);
- break;
- case NOOP_CMD:
- (void) usprintf(mp->s,Ok);
- break;
- case MAIL_CMD:
- if((cp = getname(arg)) == NULLCHAR){
- (void) usprintf(mp->s,Syntax);
- break;
- }
- free(mp->from);
- mp->from = strdup(cp);
- (void) usprintf(mp->s,Ok);
- break;
- case QUIT_CMD:
- (void) usprintf(mp->s,Closing);
- goto quit;
- case RCPT_CMD: /* Specify recipient */
- if((cp = getname(arg)) == NULLCHAR){
- (void) usprintf(mp->s,Syntax);
- break;
- }
- orig = strdup (cp);
- /* rewrite address if possible */
- if((newaddr = rewrite_address(cp)) != NULLCHAR){
- strcpy(buf,newaddr);
- cp = buf;
- free(newaddr);
- }
-
- /* check if address is ok */
- if ((address_type = validate_address(cp)) == BADADDR){
- (void) usprintf(mp->s,Unknown,cp);
- free (orig);
- break;
- }
- /* if a local address check for an alias */
- if (address_type == LOCAL)
- expandalias(&mp->to, cp, orig);
- else
- /* a remote address is added to the list */
- addlist(&mp->to, cp, address_type, orig);
-
- (void) usprintf(mp->s,Ok);
- free (orig);
- break;
- case HELP_CMD:
- (void) usprintf(mp->s,Help);
- break;
- case DATA_CMD:
- if(mp->to == NULLLIST)
- (void) usprintf(mp->s,Needrcpt);
- else if ((mp->data = tmpfile()) == NULLFILE)
- (void) usprintf(mp->s,Ioerr);
- else
- getmsgtxt(mp);
- break;
- case RSET_CMD:
- del_list(mp->to);
- mp->to = NULLLIST;
- (void) usprintf(mp->s,Reset);
- break;
- case EXPN_CMD:
- if (*arg == '\0'){
- (void) usprintf(mp->s,Syntax);
- break;
- }
-
- list = NULLLIST;
- orig = strdup (arg);
- /* rewrite address if possible */
- if((newaddr = rewrite_address(arg)) != NULLCHAR)
- if(strcmp(newaddr,arg) == 0){
- free(newaddr);
- newaddr = NULLCHAR;
- } else {
- strcpy(buf,newaddr);
- arg = buf;
- }
- list = NULLLIST;
- expandalias(&list,arg, orig);
- free (orig);
- if (strcmp(list->val,arg) == 0 && list->next == NULLLIST)
- if(newaddr == NULLCHAR){
- (void) usprintf(mp->s,Noalias,arg);
- del_list(list);
- break;
- }
- ap = list;
- while (ap->next != NULLLIST){
- (void) usprintf(mp->s,"250-%s\n",ap->val);
- ap = ap->next;
- }
- usprintf(mp->s,"250 %s\n",ap->val);
- del_list(list);
- free(newaddr);
- break;
- }
- goto loop;
-
- quit:
- log(mp->s,"close SMTP");
- close_s(mp->s);
- mail_clean(mp);
- smtptick(NULL); /* start SMTP daemon immediately */
- }
-
-
- int
- makeBBSbid (bid, line, ours)
- char *bid, *line;
- int ours;
- {
- char *cp;
- int retval = 0;
-
- *bid = 0;
- if((cp = getname(line)) == NULLCHAR)
- return retval;
- strcpy(bid,cp);
- cp = strchr(bid,'@');
- /* A trailing ".bbs" indicates that the Message-ID was generated
- * from a BBS style message, and not a RFC-822 message.
- */
- if(cp != NULLCHAR && stricmp(&bid[strlen(bid) - 4], ".bbs") == 0) {
- *cp = '\0'; /*retain the bid given by user*/
- retval = 1;
- } else {
- if (ours) {
- /*This is a message with no bid, MSGID is <msg#@hostname>
- *make this BID style 'msg#_host'
- *ie. replace @ with _ and
- *cut off after first part of hostname - WG7J
- */
- *cp = '_';
- if((cp = strchr(cp,'.')) != NULLCHAR)
- *cp = '\0';
- retval = 1;
- }
- }
- bid[13] = '\0'; /* BIDs should be no longer than 13 bytes */
- return retval;
- }
-
-
- extern char shortversion[];
- extern char *Mbfwdinfo;
-
- /* read the message text
- * This now checks for Message-Id's that could be bids
- * and deletes the message if so. - WG7J
- */
- static int
- getmsgtxt(mp)
- struct smtpsv *mp;
- {
- char buf[LINELEN];
- register char *p = buf;
- long t;
- #ifdef MBFWD
- char *cp, *cp2;
- char bid[LINELEN];
- time_t now;
- FILE *fp;
- int foundbid = 0;
- #endif
-
- /* Add timestamp; ptime adds newline */
- time(&t);
- fprintf(mp->data,Hdrs[RECEIVED]);
- if(mp->system != NULLCHAR)
- fprintf(mp->data,"from %s ",mp->system);
- #ifdef MBFWD
- fprintf(mp->data,"by %s (%s) with SMTP\n\tid AA%ld ; %s",
- Hostname, (Mbfwdinfo != NULLCHAR) ? Mbfwdinfo : shortversion, \
- get_msgid(0), ptime(&t));
- #else
- fprintf(mp->data,"by %s (%s) with SMTP\n\tid AA%ld ; %s",
- Hostname, shortversion, get_msgid(0), ptime(&t));
- #endif
- if(ferror(mp->data)) {
- (void) usprintf(mp->s,Ioerr);
- return 1;
- } else {
- (void) usprintf(mp->s,Enter);
- }
- while(1) {
- pwait (NULL);
- if(recvline(mp->s,p,sizeof(buf)) == -1)
- return 1;
- rip(p);
- /* check for end of message ie a . or escaped .. */
- if (*p == '.') {
- if (*++p == '\0') {
- #ifdef MBFWD
- /* Also sends appropriate response */
- /* if duplicate BID, do not send - WG7J */
- if (mp->dupbid)
- (void) usputs(mp->s,DupBidMsg);
- else
- #endif
- if(mailit(mp->data,mp->from,mp->to) != 0)
- (void) usputs(mp->s,Ioerr);
- else
- (void) usprintf(mp->s,Sent);
- fclose(mp->data);
- mp->data = NULLFILE;
- del_list(mp->to);
- mp->to = NULLLIST;
- #ifdef MBFWD
- /* If there is a BID set, save it in the history file - WG7J */
- if(mp->bid != NULLCHAR)
- if((fp = fopennew(Historyfile,APPEND_TEXT)) != NULL) {
- /* Timestamp added to allow automatic expiry
- * of bid file - WG7J
- */
- time(&now);
- fprintf(fp,"%-13.13s %-14ld\n",mp->bid,now); /* Save BID */
- fclose(fp);
- /* Free this bid ! */
- free(mp->bid);
- mp->bid = NULL;
- }
- #endif
- return 0;
- } else if (!(*p == '.' && *(p+1) == '\0'))
- p--;
- }
- /* for UNIX mail compatiblity */
- if (!strncmp(p,"From ",5))
- (void) putc('>',mp->data);
- /* Append to data file */
- if(fprintf(mp->data,"%s\n",p) < 0) {
- (void) usprintf(mp->s,Ioerr);
- return 1;
- }
- #ifdef MBFWD
- /* Check for Message-Id string - WG7J */
- if(!foundbid && !strnicmp(p,Hdrs[MSGID], 11)) {
- /* so we ignore any "Message ID:" in the text body,
- which occurs when we are inserting a message */
- foundbid = 1;
- if (makeBBSbid (bid, p, 0)) {
- /* now check it */
- if (Smtpbidcheck && (mp->dupbid = msgidcheck(bid)) == 0)
- mp->bid = strdup(bid);
- }
- }
- #endif
- #ifdef WPAGES
- if(MbWpages && (!strnicmp(p,"R:",2)) && (*(p+8) == '/')) { /* found one */
- /* Find the '@[:]CALL.STATE.COUNTRY'or
- * or the '?[:]CALL.STATE.COUNTRY' string
- * The : is optional. */
- if( ((cp=strchr(p,'@')) != NULLCHAR) || ((cp=strchr(p,'?')) != NULLCHAR) ) {
- if((cp2=strpbrk(cp," \n\t")) != NULLCHAR)
- *cp2 = '\0';
- /* Some bbs's send @bbs instead of @:bbs*/
- if (*++cp == ':')
- cp++;
- pwait (NULL); /* just to be nice to others */
- wpageAdd (cp, 1, 1);
- }
- }
- #endif
- }
- }
-
- /* Create control block, initialize */
- static struct smtpsv *
- mail_create()
- {
- register struct smtpsv *mp;
-
- mp = (struct smtpsv *)callocw(1,sizeof(struct smtpsv));
- mp->from = strdup(""); /* Default to null From address */
- return mp;
- }
-
- /* Free resources, delete control block */
- static void
- mail_clean(mp)
- register struct smtpsv *mp;
- {
- if (mp == NULLSMTPSV)
- return;
- free(mp->system);
- free(mp->from);
- if(mp->data != NULLFILE)
- fclose(mp->data);
- del_list(mp->to);
- free((char *)mp);
- }
-
-
- /* get status of an entry in the *.ctl file */
-
- void
- statusCtl (who, extension, info, entry, readit)
- char *who, *extension;
- struct let *info;
- int entry, readit;
- {
- register FILE *fp;
- char mailbox[100];
- int oldstatus;
-
- sprintf(mailbox,"%s/CONTROL/%s.%s",Mailspool,who, extension);
- if((fp = subdir_fopen(mailbox,(readit) ? READ_BINARY : UPDATE_TEXT)) != NULLFILE){
- fseek (fp, (long) ((entry - 1) * sizeof (struct let)), 0);
- if (readit)
- fread (info, sizeof(struct let), 1, fp);
- else {
- oldstatus = info->status;
- if (issysarea (who))
- info->status &= ~BM_READ;
- fwrite (info, sizeof(struct let), 1, fp);
- info->status = oldstatus;
- }
- fclose(fp);
- }
- }
-
- /* handle updating of the *.ctl file, here */
-
- void
- updateCtl (who, info)
- char *who;
- struct let *info;
- {
- register FILE *fp;
- char mailbox[100];
-
- pwait (NULL);
- sprintf(mailbox,"%s/CONTROL/%s.ctl",Mailspool,who);
- if((fp = subdir_fopen(mailbox,APPEND_BINARY)) != NULLFILE){
- fwrite (info, sizeof(struct let), 1, fp);
- fclose(fp);
- }
- }
-
-
- /* handle updating of the *.fwd files, here */
-
- void
- updateFwd (who, area, bid)
- char *who, *area;
- long bid;
- {
- register FILE *fp;
- char mailbox[100];
-
- pwait (NULL);
- sprintf(mailbox,"%s/%s.fwd",Mailspool,who);
- if((fp = fopen(mailbox,APPEND_TEXT)) != NULLFILE) {
- fprintf (fp, " %s %-ld\n", area, bid);
- fclose(fp);
- }
- }
-
-
- /* General mailit function. It takes a list of addresses which have already
- ** been verified and expanded for aliases. Base on the current mode the message
- ** is place in an mbox, the outbound smtp queue or the rqueue interface
- */
- static int
- mailit(data,from,tolist)
- FILE *data;
- char *from;
- struct list *tolist;
- {
- struct list *ap, *dlist = NULLLIST;
- FILE *fp, *out;
- char mailbox[50], *cp, *host, *qhost;
- char forwardto[32];
- char origaddressee[40];
- int c, fail = 0, lines, k;
- time_t t;
- extern int Smtpquiet;
- int lastWasCR, wasForwarded;
- #ifdef USERLOG
- long msgid;
- int nextisBID;
- #endif
- char *realnm, *realarea;
- int index;
- int Holdit = 0, firstIDline;
-
- struct let lt;
- long startedat, endedat;
-
- if ((Smtpmode & QUEUE) != 0)
- return(router_queue(data,from,tolist));
-
- do {
- qhost = NULLCHAR;
- for(ap = tolist;ap != NULLLIST;ap = ap->next)
- if (ap->type == DOMAIN){
- if ((host = strrchr(ap->val,'@')) != NULLCHAR)
- host++;
- else
- host = Hostname;
- if(qhost == NULLCHAR)
- qhost = host;
- if(stricmp(qhost,host) == 0){
- ap->type = BADADDR;
- addlist(&dlist,ap->val,0, ap->val);
- }
- }
- if(qhost != NULLCHAR){
- rewind(data);
- queuejob(data,qhost,dlist,from);
- del_list(dlist);
- dlist = NULLLIST;
- }
- } while(qhost != NULLCHAR);
-
- #ifdef NNTPS
- for(ap = tolist;ap != NULLLIST;ap = ap->next){
- if(ap->type != NNTP_GATE)
- continue;
- nnGpost(data,from,ap);
- ap->type = BADADDR;
- }
- #endif
-
- index = 0;
- for(ap = tolist;ap != NULLLIST;ap = ap->next,index++){
- if(ap->type != LOCAL){
- ap->type = DOMAIN;
- continue;
- }
- /* If local rewrite to CHECK, then tell SYSOP */
- if (!stricmp (ap->val, "check")) {
- rewind (data);
- rdaemon (data, NULLCHAR, NULLCHAR, "Unknown Routing", 'P', 1);
- }
- #ifdef RMAIL
- /* If local RMAIL, then leave here */
- if (!stricmp (ap->val, "rmail")) {
- if (rmail (data, from))
- continue; /* if handled by rmail() */
- }
- #endif
- #ifdef REQSVR
- /* If local REQSVR, then see if this is one supported */
- if (!stricmp (ap->val, "reqsvr")) {
- if (reqsvr (data, from))
- continue; /* if handled by reqsvr() */
- }
- #endif
- /* strip off host name of LOCAL addresses */
- if ((cp = strchr(ap->val,'@')) != NULLCHAR)
- *cp = '\0';
-
- rewind(data);
- /* replace '\' and '.' with '/',
- * this allows mailing into subdirs of spool/mail - WG7J
- */
- cp = ap->val;
- while((cp=strchr(cp,'.')) != NULLCHAR)
- *cp++ = '/';
- cp = ap->val;
- while((cp=strchr(cp,'\\')) != NULLCHAR)
- *cp++ = '/';
-
- /* truncate long user names */
- /* if (strlen(ap->val) > MBOXLEN)
- ap->val[MBOXLEN] = '\0';
- */
-
- if ((realarea = rewrite_address (ap->orig)) == NULLCHAR)
- realarea = strdup (ap->val);
-
- /* if mail file is busy save it in our smtp queue
- * and let the smtp daemon try later.
- */
- if (mlock(Mailspool,realarea)){
- addlist(&dlist,realarea,0, realarea);
- fail = queuejob(data,Hostname,dlist,from);
- del_list(dlist);
- dlist = NULLLIST;
- free (realarea);
- } else {
- char buf[LINELEN];
- int tocnt = 0;
- int chkwpages = 1;
- sprintf(mailbox,"%s/%s",Mailspool,realarea);
- nntp_name_expansion (mailbox);
- strcat(mailbox,".txt");
- #ifndef AMIGA
- if((fp = subdir_fopen(mailbox,APPEND_TEXT)) != NULLFILE){
- #else
- if((fp = subdir_fopen(mailbox,"r+")) != NULLFILE){
- #endif
- pwait (NULL);
- (void) fseek(fp, 0L, 2);
- time(&t);
- #ifdef USERLOG
- wasForwarded = nextisBID = firstIDline = 0;
- origaddressee[0] = 0;
- msgid = 0;
- lines = 0;
- for (k = 0; k < 32; k++)
- forwardto[k] = 0;
- #endif
- startedat = ftell(fp);
- fprintf(fp,"From %s %s",from,ctime(&t));
- host = NULLCHAR;
- while(fgets(buf,sizeof(buf),data) != NULLCHAR){
- pwait (NULL);
- #ifndef TNOS_68K
- lines++;
- #endif
- if(buf[0] == '\n'){
- if(tocnt == 0) {
- fprintf(fp,"%s%s\n",Hdrs[APPARTO],ap->orig);
- #ifndef TNOS_68K
- lines++;
- #endif
- }
- fputc('\n',fp);
- break;
- }
- rip(buf);
- if (htype(buf) == TO) {
- strncpy (origaddressee, &buf[4], 40);
- origaddressee[39] = 0;
- if (isgroup (origaddressee)) {
- fprintf (fp, "%s%s@%s\n%s%s-relay@%s\n%s%s-admin@%s\n", Hdrs[XMAILGROUP], origaddressee, Hostname, Hdrs[SENDER], origaddressee, Hostname, Hdrs[ERRORSTO], origaddressee, Hostname);
- #ifndef TNOS_68K
- lines += 2;
- #endif
- }
- if (chkwpages)
- realnm = wpage_exp (strdup (ap->orig), 1, 0);
- else
- realnm = strdup (ap->orig);
- fprintf (fp, "%s%s", Hdrs[TO], realnm);
- free (realnm);
- } else if (htype(buf) == MSGID) {
- long nerf;
- if (index) {
- #if 0
- msgid = get_msgid(1);
- fprintf (fp, "%s<%ld@%s>",Hdrs[MSGID],msgid,Hostname);
- #else
- nerf = get_msgid(1);
- fprintf (fp, "%s<%ld@%s>",Hdrs[MSGID],nerf,Hostname);
- #endif
- } else {
- cp = &buf[strlen(Hdrs[MSGID])];
- if (*cp == '<')
- cp++;
- nerf = atol(cp);
- #if 0
- if (nerf)
- msgid = nerf;
- #endif
- fputs(buf, fp);
- }
- } else
- fputs(buf, fp);
- #ifdef USERLOG
- if (!firstIDline && nextisBID && (cp=strstr(buf,"AA")) != NULLCHAR) {
- /*what follows is the message-number*/
- msgid = atol(cp+2);
- nextisBID = 0;
- firstIDline = 1;
- }
- #endif
- switch(htype(buf)){
- case XFORWARD: k = BBSlookup (&buf[strlen(Hdrs[XFORWARD])]);
- if (k != -1)
- forwardto[k] = 1;
- wasForwarded = 1;
- break;
- case RECEIVED:
- #ifdef USERLOG
- nextisBID = 1;
- #endif
- break;
- case BBSTYPE:
- chkwpages = 0;
- break;
- case XBBSHOLD: {
- long here;
- here = ftell (data);
- rewind (data);
- rdaemon (data, NULLCHAR, NULLCHAR, "Held Message - Forward Loop", 'P', 1);
- fseek (data, here, SEEK_SET);
- Holdit = 1;
- }
- break;
- case CC: if (origaddressee[0]) {
- if ((cp = strchr (origaddressee, '.')) != NULLCHAR)
- *cp = 0;
- fprintf (fp, ", %s", origaddressee);
- }
- case TO:
- ++tocnt;
- break;
- case RRECEIPT:
- if((cp = getaddress(buf,0))
- != NULLCHAR){
- free(host);
- host = strdup(cp);
- }
- break;
- }
- fputc('\n', fp);
- }
- while(fgets(buf,sizeof(buf),data) != NULLCHAR) {
- pwait (NULL);
- fputs(buf,fp);
- #ifndef TNOS_68K
- lines++;
- #endif
- lastWasCR = (buf[0] == '\n') ? 1 : 0;
- }
- if(ferror(fp))
- fail = 1;
- else if (!lastWasCR) {
- fprintf(fp,"\n");
- #ifndef TNOS_68K
- lines++;
- #endif
- }
- /* Leave a blank line between msgs */
- #ifdef USERLOG
- fflush (fp);
- endedat = ftell (fp);
- #endif
- fclose(fp);
-
- #ifdef USERLOG
- lt.size = (endedat - startedat - lines - 1);
- lt.status = ((isarea (realarea) && MbHolding && !wasForwarded) || Holdit) ? BM_ONHOLD : 0;
- lt.start = startedat;
- lt.bid = msgid;
- updateCtl (realarea, <);
- #endif
- if (msgid)
- for (k = 0; k < Numfwds; k++)
- if ((!forwardto[k]) && AREAlookup (realarea, k))
- updateFwd (MyFwds[k], realarea, lt.bid);
-
- /* If we use tprintf here, instead of printf, flowcontrol
- * in the command screen is used; if the system is unattended for
- * more then 24 messages coming in, it will lock up mail delivery.
- * Make sure this only goes to the command screen - WG7J
- */
- if(Current->output == Command->output)
- printf("New mail for %s from <%s>%c\n",realarea,from, Smtpquiet ? ' ' : '\007');
- if(host != NULLCHAR){
- rewind(data); /* Send return receipt */
- mdaemon(data,host,NULLLIST,0);
- free(host);
- }
- } else
- fail = 1;
- (void) rmlock(Mailspool,realarea);
- if (fail)
- break;
- smtplog("deliver: To: %s From: %s Size: %ld",realarea,from, lt.size);
- free (realarea);
- }
- }
- return fail;
- }
-
- /* Return Date/Time in Arpanet format in passed string */
- char *
- ptime(t)
- long *t;
- {
- /* Print out the time and date field as
- * "DAY day MONTH year hh:mm:ss ZONE"
- */
- register struct tm *ltm;
- static char tz[4];
- static char str[40];
- char *p, *getenv();
- /* Read the system time */
- ltm = localtime(t);
-
- if (*tz == '\0')
- if ((p = getenv("TZ")) == NULL)
- strcpy(tz,"UTC");
- else
- strncpy(tz,p,3);
-
- /* rfc 822 format */
- sprintf(str,"%s, %.2d %s %02d %02d:%02d:%02d %.3s\n",
- Days[ltm->tm_wday],
- ltm->tm_mday,
- Months[ltm->tm_mon],
- ltm->tm_year,
- ltm->tm_hour,
- ltm->tm_min,
- ltm->tm_sec,
- tz);
- return(str);
- }
-
- long
- get_msgid(type)
- int type; /* is this a sequence number (0) or a MID (1)? */
- {
- char sfilename[LINELEN];
- char s[20];
- register long sequence = 0;
- FILE *sfile;
-
- sprintf(sfilename,"%s/%s.seq",Mailqdir, (type) ? "message" : "sequence");
- sfile = fopen(sfilename,READ_TEXT);
-
- /* if sequence file exists, get the value, otherwise set it */
- if (sfile != NULL){
- (void) fgets(s,sizeof(s),sfile);
- sequence = atol(s);
- if (type) { /* use 1-65535, only */
- /* Keep it in range of and 5 digit number to use for dos name prefix with room to spare. */
- if (sequence < 0L || sequence > 65534L )
- sequence = 0;
- } else {
- /* Keep it in range of and 8 digit number to use for dos name prefix. */
- if (sequence < 0L || sequence > 99999998L )
- sequence = 0;
- }
- fclose(sfile);
- }
-
- /* increment sequence number, and write to sequence file */
- sfile = fopen(sfilename,WRITE_TEXT);
- fprintf(sfile,"%ld",++sequence);
- fclose(sfile);
- return sequence;
- }
-
- /* test if mail address is valid */
- int
- validate_address(s)
- char *s;
- {
- char *cp;
- int32 addr;
-
- if(*s == '!'){
- #ifdef NNTPS
- if((cp = strpbrk(s,"%@.,/")) != NULLCHAR)
- *cp = '\0';
- return NNTP_GATE;
- #else
- return BADADDR;
- #endif
- }
- /* if address has @ in it then check dest address */
- if ((cp = strrchr(s,'@')) != NULLCHAR){
- cp++;
- /* 1st check if it is our hostname.
- * if not then check the hosts file and see if we can
- * resolve the address to a known site or one of our aliases.
- */
- if(stricmp(cp,Hostname) != 0){
- if ((addr = mailroute(cp)) == 0
- && (Smtpmode & QUEUE) == 0)
- return BADADDR;
- if (ismyaddr(addr) == NULLIF)
- return DOMAIN;
- }
-
- /* on a local address remove the host name part */
- *--cp = '\0';
- }
-
- /* if using an external router leave address alone */
- if ((Smtpmode & QUEUE) != 0)
- return LOCAL;
-
- /* check for the user%host hack */
- if ((cp = strrchr(s,'%')) != NULLCHAR){
- *cp = '@';
- cp++;
- /* reroute based on host name following the % seperator */
- if (mailroute(cp) == 0)
- return BADADDR;
- else
- return DOMAIN;
- }
-
- #ifdef MSDOS /* dos file name checks */
- /* Check for characters illegal in MS-DOS file names */
- for(cp = s;*cp != '\0';cp++) {
- /* Accept '.', '/', and '\' !
- * that way we can mail into subdirs - WG7J
- */
- if(*cp == '.' || *cp == '\\' || *cp == '/')
- continue;
- if(dosfnchr(*cp) == 0)
- return BADADDR;
- }
- #endif
- return LOCAL;
- }
-
- /* place a mail job in the outbound queue */
- int
- queuejob(dfile,host,to,from)
- register FILE *dfile;
- char *host;
- struct list *to;
- char *from;
- {
- register FILE *fp;
- struct list *ap;
- char tmpstring[50], prefix[9], buf[LINELEN];
- register int cnt;
- long totalcnt = 0;
-
- sprintf(prefix,"%ld",get_msgid(0));
- mlock(Mailqdir,prefix);
- sprintf(tmpstring,"%s/%s.txt",Mailqdir,prefix);
- if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE){
- (void) rmlock(Mailqdir,prefix);
- return 1;
- }
- while((cnt = fread(buf, 1, LINELEN, dfile)) > 0) {
- totalcnt += cnt;
- pwait (NULL);
- if(fwrite(buf, 1, cnt, fp) != cnt)
- break;
- }
- if(ferror(fp)){
- fclose(fp);
- (void) rmlock(Mailqdir,prefix);
- return 1;
- }
- fclose(fp);
- sprintf(tmpstring,"%s/%s.wrk",Mailqdir,prefix);
- if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE){
- (void) rmlock(Mailqdir,prefix);
- return 1;
- }
- pwait (NULL);
- fprintf(fp,"%s\n%s\n",host,from);
- for(ap = to; ap != NULLLIST; ap = ap->next){
- fprintf(fp,"%s\n",ap->val);
- smtplog("queue job %s To: %s From: %s Size: %ld",prefix,ap->val,from, totalcnt);
- }
- fclose(fp);
- (void) rmlock(Mailqdir,prefix);
- return 0;
- }
-
- /* Deliver mail to the appropriate mail boxes */
- static int
- router_queue(data,from,to)
- FILE *data;
- char *from;
- struct list *to;
- {
- int c;
- register struct list *ap;
- FILE *fp;
- char tmpstring[50];
- char prefix[9];
-
- sprintf(prefix,"%ld",get_msgid(0));
- mlock(Routeqdir,prefix);
- sprintf(tmpstring,"%s/%s.txt",Routeqdir,prefix);
- if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE){
- (void) rmlock(Routeqdir,prefix);
- return 1;
- }
- rewind(data);
- pwait (NULL);
- while((c = getc(data)) != EOF)
- if(putc(c,fp) == EOF)
- break;
- pwait (NULL);
- if(ferror(fp)){
- fclose(fp);
- (void) rmlock(Routeqdir,prefix);
- return 1;
- }
- fclose(fp);
- sprintf(tmpstring,"%s/%s.wrk",Routeqdir,prefix);
- if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE){
- (void) rmlock(Routeqdir,prefix);
- return 1;
- }
- fprintf(fp,"From: %s\n",from);
- for(ap = to;ap != NULLLIST;ap = ap->next){
- fprintf(fp,"To: %s\n",ap->val);
- }
- fclose(fp);
- (void) rmlock(Routeqdir,prefix);
- smtplog("rqueue job %s From: %s",prefix,from);
- return 0;
- }
-
- /* add an element to the front of the list pointed to by head
- ** return NULLLIST if out of memory.
- */
- struct list *
- addlist(head,val,type,orig)
- struct list **head;
- char *val, *orig;
- int type;
- {
- register struct list *tp;
-
- tp = (struct list *)callocw(1,sizeof(struct list));
-
- tp->next = NULLLIST;
-
- /* allocate storage for the char string */
- tp->val = strdup(val);
- tp->type = type;
- tp->orig = strdup (orig);
-
- /* add entry to front of existing list */
- if (*head == NULLLIST)
- *head = tp;
- else {
- tp->next = *head;
- *head = tp;
- }
- return tp;
-
- }
-
- int
- isanIPhost (str)
- char *str;
- {
- char *host;
-
- /* this routine returns 1 if it looks like an IP hostname,
- otherwise it returns 0 which means it is probably an AX25 BBS name */
- if (strstr (str, ".org") && strstr (str, ".com") &&
- strstr (str, ".gov") && strstr (str, ".mil") &&
- strstr (str, ".net") && strstr (str, ".edu"))
- return 1;
- if ((host = strchr (str, '@')) != 0)
- host++;
- else
- host = str;
- if(resolve(host))
- return 1;
- return 0;
- }
-
-
- char *
- host_or_wpage_exp (to, hier, exphome)
- char *to;
- int hier;
- int exphome; /* append and expand home bbs name ? */
- {
- if (isanIPhost (to))
- return (to);
- return (wpage_exp (to, hier, exphome));
- }
-
-
- #define SKIPWORD(X) while(*X && *X!=' ' && *X!='\t' && *X!='\n' && *X!= ',') X++;
- #define SKIPSPACE(X) while(*X ==' ' || *X =='\t' || *X =='\n' || *X == ',') X++;
-
- /* check for a group and expand group into an address list */
- static struct list *
- expandgroup(head, user, orig)
- struct list **head;
- char *user, *orig;
- {
- FILE *fp;
- register char *s,*p;
- struct rr *rrp, *rrlp;
- int ingroup = 0;
- struct list *tp;
- char buf[LINELEN], *t;
-
- /* no group file found */
- if ((fp = fopen(Group, READ_TEXT)) != NULLFILE) {
- while (fgets(buf,LINELEN,fp) != NULLCHAR){
- pwait (NULL);
- p = buf;
- if (*p == '#' || *p == '\n')
- continue;
- rip(p);
-
- /* if not in an matching entry skip continuation lines */
- if (!ingroup && isspace(*p))
- continue;
-
- /* when processing an active group check for a continuation */
- if (ingroup){
- if (!isspace(*p))
- break; /* done */
- SKIPSPACE(p);
- s = p;
- SKIPWORD(p);
- if (*p != '\0')
- *p++ = '\0';
- SKIPSPACE(p);
- if (*p != 'S')
- continue;
- /* find hostname */
- #ifdef NNTPS
- if(*s == '!')
- tp = addlist(head,s,NNTP_GATE, s);
- else
- #endif
- if (strchr(s,'@') != NULLCHAR)
- tp = addlist(head,s,DOMAIN, s);
- else {
- t = wpage_exp (strdup (s), 0, 0);
- tp = addlist(head,t,LOCAL, t);
- free (t);
- }
- } else {
- s = p;
- if ((p = strchr (s, ':')) == NULLCHAR) /* say what! */
- continue;
- *p = '\0'; /* end the group name */
- if (strcmp(s,user) != 0)
- continue; /* no match go on */
- ingroup = 1;
- }
- }
- }
-
- pwait (NULL);
- if (fp)
- (void) fclose(fp);
- if (ingroup) /* found and processed an group. */
- return tp;
-
- /* no group found treat as a local address */
- return addlist(head, user, LOCAL, orig);
- }
-
- /* check for and alias and expand alias into a address list */
- struct list *
- expandalias(head, user, orig)
- struct list **head;
- char *user, *orig;
- {
- FILE *fp;
- register char *s,*p;
- struct rr *rrp, *rrlp;
- int inalias = 0;
- struct list *tp;
- char buf[LINELEN], *t;
-
- /* no alias file found */
- if ((fp = fopen(Alias, READ_TEXT)) == NULLFILE){
- /* Try MB, MG or MR domain name records */
- rrlp = rrp = resolve_mailb(user);
- while(rrp != NULLRR){
- if(rrp->rdlength > 0){
- /* remove the trailing dot */
- rrp->rdata.name[rrp->rdlength-1] = '\0';
- /* replace first dot with @ if there is no @ */
- if(strchr(rrp->rdata.name,'@') == NULLCHAR
- && (p = strchr(rrp->rdata.name,'.')) !=
- NULLCHAR)
- *p = '@';
- if(strchr(rrp->rdata.name,'@') != NULLCHAR)
- tp = addlist(head,rrp->rdata.name,
- DOMAIN, rrp->rdata.name);
- else
- tp = addlist(head,rrp->rdata.name,
- LOCAL, rrp->rdata.name);
- ++inalias;
- }
- rrp = rrp->next;
- }
- free_rr(rrlp);
- if(inalias)
- return tp;
- else
- return expandgroup(head, user, orig);
- }
-
- while (fgets(buf,LINELEN,fp) != NULLCHAR){
- p = buf;
- if ( *p == '#' || *p == '\0' || *p == '\n')
- continue;
- rip(p);
-
- /* if not in an matching entry skip continuation lines */
- if (!inalias && isspace(*p))
- continue;
-
- /* when processing an active alias check for a continuation */
- if (inalias){
- if (!isspace(*p))
- break; /* done */
- } else {
- s = p;
- SKIPWORD(p);
- *p++ = '\0'; /* end the alias name */
- if (strcmp(s,user) != 0)
- continue; /* no match go on */
- inalias = 1;
- }
-
- /* process the recipients on the alias line */
- SKIPSPACE(p);
- while(*p != '\0' && *p != '#'){
- s = p;
- SKIPWORD(p);
- if (*p != '\0')
- *p++ = '\0';
-
- /* find hostname */
- #ifdef NNTPS
- if(*s == '!')
- tp = addlist(head,s,NNTP_GATE, s);
- else
- #endif
- if (strchr(s,'@') != NULLCHAR)
- tp = addlist(head,s,DOMAIN, s);
- else {
- t = wpage_exp (strdup (s), 0, 0);
- tp = addlist(head,t,LOCAL, t);
- free (t);
- }
- SKIPSPACE(p);
- }
- }
- (void) fclose(fp);
-
- if (inalias) /* found and processed an alias. */
- return tp;
-
- /* no alias found treat as a local address */
- return expandgroup(head, user, orig);
- }
-
- #if defined(ANSIPROTO)
- static void
- smtplog(char *fmt, ...)
- {
- va_list ap;
- char *cp;
- long t;
- FILE *fp;
-
- if ((fp = fopen(Maillog,APPEND_TEXT)) == NULLFILE)
- return;
- time(&t);
- cp = ctime(&t);
- rip(cp);
- fprintf(fp,"%s ",cp);
- va_start(ap,fmt);
- vfprintf(fp,fmt,ap);
- va_end(ap);
- fprintf(fp,"\n");
- fclose(fp);
- }
-
- #else
-
- static void
- smtplog(fmt,arg1,arg2,arg3,arg4)
- char *fmt;
- int arg1,arg2,arg3,arg4;
- {
- char *cp;
- long t;
- FILE *fp;
-
- if ((fp = fopen(Maillog,APPEND_TEXT)) == NULLFILE)
- return;
- time(&t);
- cp = ctime(&t);
- rip(cp);
- fprintf(fp,"%s ",cp);
- fprintf(fp,fmt,arg1,arg2,arg3,arg4);
- fprintf(fp,"\n");
- fclose(fp);
- }
- #endif
-
- /* send mail to a single user. Can be called from the ax25 mailbox or
- ** from the return mail function in the smtp client
- */
- int
- mailuser(data,from,to, origto)
- FILE *data;
- char *from;
- char *to, *origto;
- {
-
- int address_type, ret;
- struct list *tolist = NULLLIST;
-
- /* check if address is ok */
- if ((address_type = validate_address(to)) == BADADDR){
- return 1;
- }
- /* if a local address check for an alias */
- if (address_type == LOCAL)
- expandalias(&tolist, to, origto);
- else
- /* a remote address is added to the list */
- addlist(&tolist, to, address_type, origto);
- ret = mailit(data,from,tolist);
- del_list(tolist);
- return ret;
-
- }
-
- /* Mailer daemon return mail mechanism */
- int
- mdaemon(data,to,lp,bounce)
- FILE *data; /* pointer to rewound data file */
- char *to; /* Overridden by Errors-To: line if bounce is true */
- struct list *lp; /* error log for failed mail */
- int bounce; /* True for failed mail, otherwise return receipt */
- {
- time_t t;
- FILE *tfile;
- char buf[LINELEN], *cp, *newto = NULLCHAR;
- int cnt;
- if(to == NULLCHAR || (to != NULLCHAR && *to == '\0') || bounce){
- while(fgets(buf,sizeof(buf),data) != NULLCHAR){
- if(buf[0] == '\n')
- break;
- /* Look for Errors-To: */
- if(htype(buf) == ERRORSTO &&
- (cp = getaddress(buf,0)) != NULLCHAR){
- free(newto);
- newto = strdup(cp);
- break;
- }
- }
- if(newto == NULLCHAR && ((to != NULLCHAR && *to == '\0') ||
- to == NULLCHAR))
- return -1;
- rewind(data);
- }
- if((tfile = tmpfile()) == NULLFILE)
- return -1;
- time(&t);
- fprintf(tfile,"%s%s",Hdrs[DATE],ptime(&t));
- fprintf(tfile,"%s<%ld@%s>\n",Hdrs[MSGID],get_msgid(1),Hostname);
- fprintf(tfile,DAEMONSTR,Hdrs[FROM],Hostname);
- fprintf(tfile,"%s%s\n",Hdrs[TO],newto != NULLCHAR ? newto : to);
- fprintf(tfile,"%s%s\n\n",Hdrs[SUBJECT],
- bounce ? "Failed mail" : "Return receipt");
- if(bounce){
- fprintf(tfile," ===== transcript follows =====\n\n");
- for (; lp != NULLLIST; lp = lp->next)
- fprintf(tfile,"%s\n",lp->val);
- fprintf(tfile,"\n");
- }
- fprintf(tfile," ===== %s follows ====\n",
- bounce ? "Unsent message" : "Message header");
-
- while(fgets(buf,sizeof(buf),data) != NULLCHAR){
- if(buf[0] == '\n')
- break;
- fputs(buf,tfile);
- }
- if(bounce){
- fputc('\n',tfile);
- while((cnt = fread(buf,1,sizeof(buf),data)) > 0)
- fwrite(buf,1,cnt,tfile);
- }
- fseek(tfile,0L,0);
- /* A null From<> so no looping replys to MAIL-DAEMONS */
- (void) mailuser(tfile,"",newto != NULLCHAR ? newto : to,newto != NULLCHAR ? newto : to);
- fclose(tfile);
- free(newto);
- return 0;
- }
- #ifdef MSDOS
- static int
- dosfnchr(ch)
- int ch;
- {
- int i, j;
-
- i = (ch & 0xf8) >> 3;
- j = doschars[i] & (1 << (ch & 0x07));
- return j;
- }
- #endif
-